import ast

from detect import detect_call
from utils.logger import get_logger
from utils.utils import get_module, get_call_name

logger = get_logger()


class NodeVisitor(ast.NodeVisitor):
    def __init__(self, path):
        self.path = path
        self.context = {}
        self.namespace = get_module(path=path)
        self.aliases = {}
        self.imports = set()
        self.dangercalls = []

    def visit_ClassDef(self, node):  # 遍历一个类结点
        # 初始命名空间加类名作为类的命名空间
        self.namespace = self.namespace + '.' + node.name
        self.generic_visit(node)

    def visit_FunctionDef(self, node):  # 遍历一个函数结点
        # 初始命名空间加函数名作为函数的命名空间
        self.context['function'] = node  # 储存函数信息
        self.context['full_function'] = self.namespace + '.' + node.name  # 储存完整函数名
        self.context['function_name'] = node.name  # 储存函数名
        self.namespace = self.namespace + '.' + node.name
        self.generic_visit(node)

    def visit_Call(self, node):
        self.context['call'] = node
        self.context['full_call'] = get_call_name(node, self.aliases)
        self.context['call_name'] = self.context['full_call'].split('.')[-1]
        api_num = detect_call(self.context['full_call'])
        if api_num:
            self.dangercalls.append(api_num)
            logger.warning(
                'File %s has a dangerous api %s with type %s in line %s!' % (
                    self.path, self.context['full_call'], api_num, str(node.lineno)))
        self.generic_visit(node)

    def visit_Import(self, node):  # 遍历一个导入结点
        for import_name in node.names:
            if import_name.asname:
                # 如果该导入项使用as进行改名，在aliases中添加改名后的名称与改名前名称的映射
                self.aliases[import_name.asname] = import_name.name
            self.imports.add(import_name.name)
            self.context['module'] = import_name.name
        self.generic_visit(node)

    def visit_ImportFrom(self, node):  # 遍历一个函数导入结点
        # if node.module is None:
        # 如果导入的模块为空(from . import ...)，直接调用visit_Import函数
        #     return self.visit_Import(node)

        for alias in node.names:
            if alias.asname:
                # 如果使用as进行改名，在aliases中添加改名后的名称与改名前名称的映射
                if node.module:
                    self.aliases[alias.asname] = node.module + '.' + alias.name
                else:
                    self.aliases[alias.asname] = alias.name
            else:
                # 如果未使用as进行改名，在aliases中添加函数名与完整函数名的映射
                if node.module:
                    self.aliases[alias.name] = node.module + '.' + alias.name
                else:
                    self.aliases[alias.name] = alias.name
            if node.module:
                self.imports.add(node.module + '.' + alias.name)
            else:
                self.imports.add(alias.name)
            self.context['module'] = node.module
            self.context['package'] = alias.name
        self.generic_visit(node)

    # def visit_Str(self, node):
    #     self.context['str'] = node.s
    #
    # def visit_Bytes(self, node):
    #     self.context['bytes'] = node.s
